/*
 * Copyright (c) 2011 Junichiro Okuno
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation are those of the
 * authors and should not be interpreted as representing official policies, either expressed
 * or implied, of Junichiro Okuno.
 */

package tcp_net.mail.smtp.client;

import tcp_net.Client;
import tcp_net.mail.smtp.debug.DebugInfo;
import tcp_net.mail.smtp.client.commands.*;
import java.util.List;
import java.util.ArrayList;

/**
	This class provides to relay an email message to another SMTP server.
	@author J. Okuno
*/
public class SMTPClient extends Client
{
	/**
		Debug information
	*/
	private final static boolean DEBUG = DebugInfo.SMTP_CLIENT_DEBUG;
	
	/**
		A default SMTP port
	*/
	public static final int SMTP_PORT = 25;
	
	/**
		Init the SMTP client
		@param hostName a server to be connected
		@param port a port number of connectiong server
	*/
	public SMTPClient(String hostName, int port)
	{
		super(hostName, port);
		DebugInfo.print(DEBUG,"SMTPClient created.");
	}
	
	/**
		Init the SMTP client with default port number: 25
		@param hostName a server to be connected
	*/
	public SMTPClient(String hostName)
	{
		this(hostName, SMTP_PORT);
	}
	
	/**
		This method provides to send an email message to another SMTP server
		@param mail_from an email address of origin
		@param rcpts a list of rcpt email addresses
		@param msg an email message
		@return true if a message is sent
	*/
	public boolean sendMessage(String mail_from, List<String> rcpts, String msg)
	{
		connect();
		List<String> outputs = receive();
		
		if(outputs.get(0).startsWith("220"))
		{
		 //EHLO
		 if(createCommand(new EHLO(mail_from), "250")) 
		 { 
			List<String> out;
			do { out = receive(); }
			while(!out.get(out.size()-1).startsWith("250 8BITMIME"));
			
			DebugInfo.print(DEBUG,"SMTP client: EHLO");
			
			//if 250, MAIL FROM
			if(createCommand(new MAIL(mail_from), "250"))
			{
				DebugInfo.print(DEBUG,"SMTP client: MAIL: "+mail_from);
				
				//if 250, RCPT TO: (loop until all RCPT addresses transmitted)
				for(String r: rcpts)
				{
					DebugInfo.print(DEBUG,"SMTP client: RCPT: "+r);
					if(!createCommand(new RCPT(r) ,"250"))
					{
						return false;
					}
				}
				
				//if 250, DATA
				if(createCommand(new DATA(null) ,"354"))
				{
					DebugInfo.print(DEBUG,"SMTP client: DATA");
					
					//if 354, send msg
					if(createCommand(new DATA(msg) ,"250"))
					{
						DebugInfo.print(DEBUG,"SMTP client: send message: "+msg);
						
						//if 250, QUIT
						if(createCommand(new QUIT() ,"221"))
						{
							DebugInfo.print(DEBUG,"SMTP client: QUIT");
							close();
							return true;
						}
					}
				}
			 }
		 }
		}
		
		//QUIT (something is wrong...)
		DebugInfo.print(DEBUG,"SMTP client: QUIT (something is wrong)");
		createCommand(new QUIT() ,"221");
		close();
		return false;
	}
	
	/**
		This method provides to help sendMessage() method
		@param command a command to be executed
		@param reply_code an SMTP reply command
		@return true if a command is executed
	*/
	private boolean createCommand(SMTPClientCommand command, String reply_code)
	{
		DebugInfo.print(DEBUG,"createCommand() withd reply code: "+reply_code);
		
		for(String cmd : command.execute())
		{
			DebugInfo.print(DEBUG,"Command: "+cmd);
			
			//Send email header and message
			if(command instanceof DATA && reply_code.equals("250"))
			{
				if(cmd.charAt(cmd.length()-1)=='\n')
				{
					cmd = cmd.substring(0, cmd.length()-2);
				}
			}
	
			List<String> outputs = converse(cmd);
			
			if(outputs.size()>0)
			{
					if(outputs.get(0).startsWith(reply_code)) 
					{ 
						DebugInfo.print(DEBUG,"Repy code ok.");
						return true; 
					}
					else
					{
						DebugInfo.print(DEBUG,"Wrong repy code: "+reply_code);
						return false;
					}
				
			}
			
			else 
			{ 
				DebugInfo.print(DEBUG,"No output");
				return false; 
			}
		}
		
		DebugInfo.print(DEBUG,"Command unabled to be executed");
		return false;
	}
}